-
Notifications
You must be signed in to change notification settings - Fork 707
Updating dice example based on Updated Specification for the reference application
#8099
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
dice exampledice example based on Updated Specification for the reference application
ddae343 to
a337ba6
Compare
dice example based on Updated Specification for the reference applicationdice example based on Updated Specification for the reference application
|
@lightsta1ker, I won't have time to review it further until I am back from KubeCon NA. Hopefully other @open-telemetry/go-approvers are going to help with reviews. |
|
Sure, @pellared . Thank you for the review & suggestions! |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The normative review is completed, with additional notes:
According to the specification requirements, support for the OTLP exporter is needed. Currently, this part is not yet supported, but I believe it can be fully implemented through a separate PR.
|
@lightsta1ker We still have some issues to resolve, including CI checks. |
|
@flc1125 I thought those checks were not relevant to this PR as it's not customer facing. |
They are relevant. |
|
Updated with fixes for failing lint checks and error handling. Also rebased. |
|
@pellared Is changelog needed? |
No |
| w.Header().Set("Content-Type", "application/json") | ||
| w.WriteHeader(http.StatusBadRequest) | ||
| msg := "Parameter rolls must be a positive integer" | ||
| _ = json.NewEncoder(w).Encode(map[string]string{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Proper error handling is missing here (500 Internal Server Error).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pellared Isn't it refering to this line -
if rolls is set to an invalid input (not a number): status code 400 and {"status": "error", "message": "Parameter rolls must be a positive integer"} ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean if the json encoding fails then it is an internal server error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought that the chances of static map encoding failure is very less. Can I handle it like this?
if err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
msg := "Parameter rolls must be a positive integer"
resp := map[string]string{
"status": "error",
"message": msg,
}
if encErr := json.NewEncoder(w).Encode(resp); encErr != nil {
logger.ErrorContext(r.Context(), "failed to write error JSON", "error", encErr)
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
logger.WarnContext(r.Context(), msg)
return
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR updates the dice example application to align with the updated specification for the OpenTelemetry reference application. The changes modernize the API design, improve observability instrumentation, and add configurable deployment options.
Key Changes
- Refactored HTTP handler to use query parameters (
rollsandplayer) instead of path parameters, with JSON responses - Enhanced OpenTelemetry instrumentation with additional metrics (histogram for dice outcomes, gauge for last rolls value) and proper resource configuration
- Added configurable port via
APPLICATION_PORTenvironment variable for flexible deployment
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| examples/dice/uninstrumented/rolldice.go | Refactored handler to parse query params, return JSON responses, added input validation with max rolls limit, and separated concerns with helper functions |
| examples/dice/uninstrumented/main.go | Added configurable port support and updated route registration to single /rolldice endpoint |
| examples/dice/instrumented/rolldice.go | Applied same refactoring as uninstrumented version, upgraded to math/rand/v2, added histogram and gauge metrics, improved telemetry context propagation |
| examples/dice/instrumented/otel.go | Added resource configuration with environment, process, host, and SDK information; updated all provider constructors to accept resource parameter |
| examples/dice/instrumented/main.go | Added configurable port support and simplified route registration to single endpoint |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if err := json.NewEncoder(w).Encode(v); err != nil { | ||
| w.WriteHeader(http.StatusInternalServerError) | ||
| log.Printf("ERROR: %v", err) | ||
| } |
Copilot
AI
Nov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The HTTP status code should be set before writing the response body. Setting WriteHeader after json.NewEncoder(w).Encode() has already written data will have no effect, as headers are sent with the first write. Move the WriteHeader call before the Encode call.
| if err := json.NewEncoder(w).Encode(v); err != nil { | |
| w.WriteHeader(http.StatusInternalServerError) | |
| log.Printf("ERROR: %v", err) | |
| } | |
| data, err := json.Marshal(v) | |
| if err != nil { | |
| w.WriteHeader(http.StatusInternalServerError) | |
| w.Header().Set("Content-Type", "application/json") | |
| _ = json.NewEncoder(w).Encode(map[string]string{ | |
| "status": "error", | |
| "message": "Internal Server Error", | |
| }) | |
| log.Printf("ERROR: %v", err) | |
| return | |
| } | |
| w.Header().Set("Content-Type", "application/json") | |
| w.WriteHeader(http.StatusOK) | |
| _, _ = w.Write(data) |
| func writeJSON(ctx context.Context, w http.ResponseWriter, v any) { | ||
| if err := json.NewEncoder(w).Encode(v); err != nil { | ||
| w.WriteHeader(http.StatusInternalServerError) | ||
| logger.ErrorContext(ctx, "json encode failed", "error", err) | ||
| } |
Copilot
AI
Nov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The HTTP status code should be set before writing the response body. Setting WriteHeader after json.NewEncoder(w).Encode() has already written data will have no effect, as headers are sent with the first write. Move the WriteHeader call before the Encode call.
| } else { | ||
| logger.DebugContext(r.Context(), "player rolled dice", "player", player, "results", results) | ||
| } | ||
| logger.InfoContext(r.Context(), "Some player rolled a dice.") |
Copilot
AI
Nov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Inconsistent logging format compared to the uninstrumented version. The uninstrumented version logs request details like "INFO: GET /rolldice?rolls=5 -> 200 OK" (line 50), while the instrumented version logs a generic message. Consider maintaining similar informative logging for consistency across both examples.
| logger.InfoContext(r.Context(), "Some player rolled a dice.") | |
| logger.InfoContext( | |
| r.Context(), | |
| "Request handled", | |
| "method", r.Method, | |
| "path", r.URL.Path+"?"+r.URL.RawQuery, | |
| "status", "200 OK", | |
| ) |
| res, _ := resource.New(ctx, | ||
| resource.WithFromEnv(), // reads OTEL_SERVICE_NAME & OTEL_RESOURCE_ATTRIBUTES. | ||
| resource.WithProcess(), | ||
| resource.WithHost(), | ||
| resource.WithTelemetrySDK(), | ||
| ) |
Copilot
AI
Nov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error returned by resource.New() is being silently ignored. This could lead to using a nil or incomplete resource, potentially causing issues with telemetry data. Either handle the error properly or at minimum log it if you intend to continue with a partial resource.
| res, _ := resource.New(ctx, | |
| resource.WithFromEnv(), // reads OTEL_SERVICE_NAME & OTEL_RESOURCE_ATTRIBUTES. | |
| resource.WithProcess(), | |
| resource.WithHost(), | |
| resource.WithTelemetrySDK(), | |
| ) | |
| res, resErr := resource.New(ctx, | |
| resource.WithFromEnv(), // reads OTEL_SERVICE_NAME & OTEL_RESOURCE_ATTRIBUTES. | |
| resource.WithProcess(), | |
| resource.WithHost(), | |
| resource.WithTelemetrySDK(), | |
| ) | |
| if resErr != nil { | |
| handleErr(resErr) | |
| return shutdown, resErr | |
| } |
|
|
||
| rollsAttr := attribute.Int("rolls", rolls) | ||
| span.SetAttributes(rollsAttr) | ||
| rollCnt.Add(ctx, 1, metric.WithAttributes(rollsAttr)) |
Copilot
AI
Nov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The counter is being incremented by 1 regardless of the number of rolls performed. This doesn't accurately represent the total number of dice rolls. Consider incrementing by the number of actual rolls: rollCnt.Add(ctx, int64(rolls), metric.WithAttributes(rollsAttr))
| rollCnt.Add(ctx, 1, metric.WithAttributes(rollsAttr)) | |
| rollCnt.Add(ctx, int64(rolls), metric.WithAttributes(rollsAttr)) |
| results, err := rolldice(rolls) | ||
| if err != nil { | ||
| w.WriteHeader(http.StatusInternalServerError) | ||
| log.Printf("ERROR: %v", err) | ||
| return | ||
| } |
Copilot
AI
Nov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing Content-Type header before writing response. The handler should set w.Header().Set("Content-Type", "application/json") before calling writeJSON to properly indicate the response format, especially for error responses.
| if err != nil { | ||
| w.WriteHeader(http.StatusInternalServerError) |
Copilot
AI
Nov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing Content-Type header before writing response. The handler should set w.Header().Set("Content-Type", "application/json") before calling writeJSON to properly indicate the response format, especially for error responses.
| if err != nil { | |
| w.WriteHeader(http.StatusInternalServerError) | |
| if err != nil { | |
| w.Header().Set("Content-Type", "application/json") | |
| w.WriteHeader(http.StatusInternalServerError) | |
| msg := "Internal server error" | |
| _ = json.NewEncoder(w).Encode(map[string]string{ | |
| "status": "error", | |
| "message": msg, | |
| }) |
|
|
||
| lastRollsGauge, err = meter.Int64ObservableGauge( | ||
| "dice.last.rolls", | ||
| metric.WithDescription("The last rolls value observed"), |
Copilot
AI
Nov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The description "The last rolls value observed" is unclear. Consider clarifying what "rolls value" means, e.g., "The number of dice rolled in the most recent request" to better describe what this gauge represents.
| metric.WithDescription("The last rolls value observed"), | |
| metric.WithDescription("The number of dice rolled in the most recent request"), |
| } else { | ||
| logger.DebugContext(r.Context(), "player rolled dice", "player", player, "results", results) | ||
| } | ||
| logger.InfoContext(r.Context(), "Some player rolled a dice.") |
Copilot
AI
Nov 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The log message "Some player rolled a dice" is generic and doesn't add useful information beyond what's already logged in lines 105-108. Consider either making this message more specific (e.g., include the request status or outcome summary) or removing it to avoid redundant logging.
| logger.InfoContext(r.Context(), "Some player rolled a dice.") |
Addresses #7937